#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <errno.h>
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
  struct sockaddr_in6 serv_addr, client_addr;
  int ls, s, tam, pid;
  char c, buffer[100];
  FILE *log;
  time_t agora;

  unlink("mobilidade-server.log");
  pid = fork();
  if (pid < 0) {
    printf("Erro ao dividir processo.\n");
    return -1;
  }
  if (pid == 0) {
    if ((s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP)) < 0) {
      printf("[TCP] Erro na criacao do socket servidor (%s).\n", strerror(errno));
      agora = time(NULL);
      log = fopen("mobilidade-server.log", "a+");
      fprintf(log, "[%s] [TCP] Erro na criacao do socket servidor (%s).\n", asctime(localtime(&agora)), strerror(errno));
      fclose(log);
      exit(0);
    }

    serv_addr.sin6_family = AF_INET6;
    serv_addr.sin6_addr = in6addr_any;
    serv_addr.sin6_port = htons(10001);

    if (bind(s, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
      printf("[TCP] Erro no bind do servidor.\n");
      agora = time(NULL);
      log = fopen("mobilidade-server.log", "a+");
      fprintf(log, "[%s] [TCP] Erro no bind do servidor.\n", asctime(localtime(&agora)));
      fclose(log);
      exit(0);
    }

    listen(s, 2);

    while (1) {
      tam = sizeof(client_addr);
      ls = accept(s, (struct sockaddr *)&client_addr, (size_t *)&tam);
      if (ls < 0)
        continue;
      while (1) {
        memset(&buffer, 0, sizeof(buffer));
        tam = recv(ls, &buffer, sizeof(buffer), 0);
        if (tam > 0) {
          printf("[TCP] Mensagem recebida de %i: %s\n", ls, buffer);
          agora = time(NULL);
          log = fopen("mobilidade-server.log", "a+");
          fprintf(log, "[%s] [TCP] Mensagem recebida de %i: %s\n", asctime(localtime(&agora)), ls, buffer);
          fclose(log);
        } else {
          if (tam == 0) {
            printf("[TCP] Erro ao receber pacote de %i. Provavel queda do cliente.\n", ls);
            agora = time(NULL);
            log = fopen("mobilidade-server.log", "a+");
            fprintf(log, "[%s] [TCP] Erro ao receber pacote de %i. Provavel queda do cliente.\n", asctime(localtime(&agora)), ls);
            fclose(log);
          } else {
            printf("[TCP] Erro ao receber pacote de %i: %s\n", ls, strerror(errno));
            agora = time(NULL);
            log = fopen("mobilidade-server.log", "a+");
            fprintf(log, "[%s] [TCP] Erro ao receber pacote de %i: %s\n", asctime(localtime(&agora)), ls, strerror(errno));
            fclose(log);
          }
          close(ls);
          break;
        }
      }
    }
  } else { 
    s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
    if (!s)
      printf("[UDP] Erro na criacao do socket servidor (%s).\n", strerror(errno));
  
    serv_addr.sin6_family = AF_INET6;
    serv_addr.sin6_addr = in6addr_any;
    serv_addr.sin6_port = htons(10002);

    if (bind(s, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
      printf("[UDP] Erro no bind do servidor.\n");
      agora = time(NULL);
      log = fopen("mobilidade-server.log", "a+");
      fprintf(log, "[%s] [UDP] Erro no bind do servidor.\n", asctime(localtime(&agora)));
      fclose(log);
      exit(0);
    }

    while (1) {
      memset(buffer, '\0', sizeof(buffer));
      tam = sizeof(client_addr);
      if (recvfrom(s, buffer, sizeof(buffer), 0, (struct sockaddr *)&client_addr, (size_t *)&tam) > 0) {
        printf("[UDP] Mensagem recebida: %s\n", buffer);
        agora = time(NULL);
        log = fopen("mobilidade-server.log", "a+");
        fprintf(log, "[%s] [UDP] Mensagem recebida: %s\n", asctime(localtime(&agora)), buffer);
        fclose(log);
      } else {
        printf("[UDP] Erro ao receber pacote: %s.\n", ls, strerror(errno));
        agora = time(NULL);
        log = fopen("mobilidade-server.log", "a+");
        fprintf(log, "[%s] [UDP] Erro ao receber pacote: %s.\n", asctime(localtime(&agora)), ls, strerror(errno));
        fclose(log);
      }
    }
  }
  system("PAUSE");	
  return 0;
}
